home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / pine3.07 / pico / word.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-09  |  16.0 KB  |  538 lines

  1. /*
  2.  * Program:    Word at a time routines
  3.  *
  4.  * Modifier:    Michael Seibel
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: mikes@cac.washington.edu
  11.  *
  12.  * Date:    19 Jan 1991
  13.  * Last Edited:    6 Jan 1992
  14.  *
  15.  * Copyright 1991 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35. /*
  36.  * The routines in this file implement commands that work word at a time.
  37.  * There are all sorts of word mode commands. If I do any sentence and/or
  38.  * paragraph mode commands, they are likely to be put in this file.
  39.  */
  40.  
  41. #include        <stdio.h>
  42. #include        "estruct.h"
  43. #include        "pico.h"
  44. #include        <ctype.h>
  45. #include    "edef.h"
  46. #include    "osdep.h"
  47.  
  48.  
  49. /* Word wrap on n-spaces. Back-over whatever precedes the point on the current
  50.  * line and stop on the first word-break or the beginning of the line. If we
  51.  * reach the beginning of the line, jump back to the end of the word and start
  52.  * a new line.  Otherwise, break the line at the word-break, eat it, and jump
  53.  * back to the end of the word.
  54.  * Returns TRUE on success, FALSE on errors.
  55.  */
  56. wrapword(n)
  57. int n;
  58. {
  59.         register int cnt;    /* size of word wrapped to next line */
  60.     register int mvdot = 0;
  61.  
  62.     /* backup from the <NL> 1 char */
  63.     if(curwp->w_doto < llength(curwp->w_dotp)){
  64.         mvdot++;
  65.         setmark(FALSE, 1);
  66.         gotoeol(FALSE, 1);
  67.     }
  68.  
  69.     if(curwp->w_doto <= 0)
  70.       return(FALSE);
  71.     else
  72.       if (!backchar(0, 1))
  73.             return(FALSE);
  74.  
  75.     /* back up until we aren't in a word,
  76.        make sure there is a break in the line */
  77.         cnt = 0;
  78.     /*
  79.      * the other way, comma's and such get munched when the line is
  80.      * wrapped because of the subsequent ldelete() of whitespace...
  81.      * 
  82.      * this is sort of ugly.  the idea is to wrap on the first space 
  83.      * before fillcol, unless that space is where the original dot
  84.      * was (otherwise wrapping can happen in the middle of the word 
  85.      * being typed).
  86.      */
  87.     while ((!isspace(lgetc(curwp->w_dotp, curwp->w_doto)) 
  88.            || (isspace(lgetc(curwp->w_dotp, curwp->w_doto)) 
  89.            && curwp->w_doto ==  curwp->w_marko))
  90.            || curwp->w_doto > fillcol){    /* break BEFORE fillcol */
  91.         cnt++;
  92.         if(curwp->w_doto <= 0){        /* no good break point */
  93.         if(mvdot)            /* put dot back! */
  94.           swapmark(0, 1);
  95.         else
  96.           while(cnt--)
  97.             forwchar(0, 1);
  98.         return(FALSE);
  99.         }
  100.         else
  101.           if (!backchar(0, 1))
  102.         return(FALSE);
  103.         }
  104.  
  105.     /* delete the forward space */
  106.         if (!ldelete(1, 0))
  107.       return(FALSE);
  108.  
  109.     /* put in a end of line */
  110.         if (!newline(0, 1))
  111.       return(FALSE);
  112.     if(mvdot){
  113.         joinlines();
  114.         swapmark(0, 1);
  115.     }
  116.     else{
  117.         /* and past the first word */
  118.         while (cnt-- > 0) {
  119.         if (forwchar(FALSE, 1) == FALSE)
  120.           return(FALSE);
  121.         }
  122.         joinlines();
  123.         }
  124.         return(TRUE);
  125. }
  126.  
  127.  
  128. /*
  129.  * joinlines - if the line below dotp fits onto the line pointed to by
  130.  *           dotp, do it
  131.  */
  132. joinlines()
  133. {
  134.     struct LINE *odotp;                /* have to use these, cause */
  135.     int    odoto;                /* mark[op] might be in use */
  136.     register int cnt;
  137.  
  138.     /* 
  139.      * tack on the line below if there is a line below, it's short
  140.      * enough to fit on this line, AND it doesn't start with 
  141.      * white space...
  142.      */
  143.     if(lforw(curwp->w_dotp) != curbp->b_linep) 
  144.       if(!isspace(lgetc(lforw(curwp->w_dotp), 0)))
  145.     if(cnt = llength(lforw(curwp->w_dotp)))
  146.       if(cnt+llength(curwp->w_dotp) < fillcol){
  147.           odotp = curwp->w_dotp;
  148.           odoto = curwp->w_doto;
  149.           gotoeol(FALSE, 1);
  150.           ldelete(1, FALSE);        /* blast <NL> */
  151.           linsert(1, ' ');            /* replace it with ' ' */
  152.           curwp->w_dotp = odotp;
  153.           curwp->w_doto = odoto;
  154.       }
  155.  
  156. }
  157.  
  158.  
  159. /*
  160.  * Move the cursor backward by "n" words. All of the details of motion are
  161.  * performed by the "backchar" and "forwchar" routines. Error if you try to
  162.  * move beyond the buffers.
  163.  */
  164. backword(f, n)
  165. {
  166.         if (n < 0)
  167.                 return (forwword(f, -n));
  168.         if (backchar(FALSE, 1) == FALSE)
  169.                 return (FALSE);
  170.         while (n--) {
  171.                 while (inword() == FALSE) {
  172.                         if (backchar(FALSE, 1) == FALSE)
  173.                                 return (FALSE);
  174.                 }
  175.                 while (inword() != FALSE) {
  176.                         if (backchar(FALSE, 1) == FALSE)
  177.                                 return (FALSE);
  178.                 }
  179.         }
  180.         return (forwchar(FALSE, 1));
  181. }
  182.  
  183. /*
  184.  * Move the cursor forward by the specified number of words. All of the motion
  185.  * is done by "forwchar". Error if you try and move beyond the buffer's end.
  186.  */
  187. forwword(f, n)
  188. {
  189.         if (n < 0)
  190.                 return (backword(f, -n));
  191.         while (n--) {
  192. #if    NFWORD
  193.                 while (inword() != FALSE) {
  194.                         if (forwchar(FALSE, 1) == FALSE)
  195.                                 return (FALSE);
  196.                 }
  197. #endif
  198.                 while (inword() == FALSE) {
  199.                         if (forwchar(FALSE, 1) == FALSE)
  200.                                 return (FALSE);
  201.                 }
  202. #if    NFWORD == 0
  203.                 while (inword() != FALSE) {
  204.                         if (forwchar(FALSE, 1) == FALSE)
  205.                                 return (FALSE);
  206.                 }
  207. #endif
  208.         }
  209.     return(TRUE);
  210. }
  211.  
  212. /*
  213.  * Move the cursor forward by the specified number of words. As you move,
  214.  * convert any characters to upper case. Error if you try and move beyond the
  215.  * end of the buffer. Bound to "M-U".
  216.  */
  217. upperword(f, n)
  218. {
  219.         register int    c;
  220.  
  221.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  222.         return(rdonly());    /* we are in read only mode    */
  223.         if (n < 0)
  224.                 return (FALSE);
  225.         while (n--) {
  226.                 while (inword() == FALSE) {
  227.                         if (forwchar(FALSE, 1) == FALSE)
  228.                                 return (FALSE);
  229.                 }
  230.                 while (inword() != FALSE) {
  231.                         c = lgetc(curwp->w_dotp, curwp->w_doto);
  232.                         if (c>='a' && c<='z') {
  233.                                 c -= 'a'-'A';
  234.                                 lputc(curwp->w_dotp, curwp->w_doto, c);
  235.                                 lchange(WFHARD);
  236.                         }
  237.                         if (forwchar(FALSE, 1) == FALSE)
  238.                                 return (FALSE);
  239.                 }
  240.         }
  241.         return (TRUE);
  242. }
  243.  
  244. /*
  245.  * Move the cursor forward by the specified number of words. As you move
  246.  * convert characters to lower case. Error if you try and move over the end of
  247.  * the buffer. Bound to "M-L".
  248.  */
  249. lowerword(f, n)
  250. {
  251.         register int    c;
  252.  
  253.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  254.         return(rdonly());    /* we are in read only mode    */
  255.         if (n < 0)
  256.                 return (FALSE);
  257.         while (n--) {
  258.                 while (inword() == FALSE) {
  259.                         if (forwchar(FALSE, 1) == FALSE)
  260.                                 return (FALSE);
  261.                 }
  262.                 while (inword() != FALSE) {
  263.                         c = lgetc(curwp->w_dotp, curwp->w_doto);
  264.                         if (c>='A' && c<='Z') {
  265.                                 c += 'a'-'A';
  266.                                 lputc(curwp->w_dotp, curwp->w_doto, c);
  267.                                 lchange(WFHARD);
  268.                         }
  269.                         if (forwchar(FALSE, 1) == FALSE)
  270.                                 return (FALSE);
  271.                 }
  272.         }
  273.         return (TRUE);
  274. }
  275.  
  276. /*
  277.  * Move the cursor forward by the specified number of words. As you move
  278.  * convert the first character of the word to upper case, and subsequent
  279.  * characters to lower case. Error if you try and move past the end of the
  280.  * buffer. Bound to "M-C".
  281.  */
  282. capword(f, n)
  283. {
  284.         register int    c;
  285.  
  286.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  287.         return(rdonly());    /* we are in read only mode    */
  288.         if (n < 0)
  289.                 return (FALSE);
  290.         while (n--) {
  291.                 while (inword() == FALSE) {
  292.                         if (forwchar(FALSE, 1) == FALSE)
  293.                                 return (FALSE);
  294.                 }
  295.                 if (inword() != FALSE) {
  296.                         c = lgetc(curwp->w_dotp, curwp->w_doto);
  297.                         if (c>='a' && c<='z') {
  298.                                 c -= 'a'-'A';
  299.                                 lputc(curwp->w_dotp, curwp->w_doto, c);
  300.                                 lchange(WFHARD);
  301.                         }
  302.                         if (forwchar(FALSE, 1) == FALSE)
  303.                                 return (FALSE);
  304.                         while (inword() != FALSE) {
  305.                                 c = lgetc(curwp->w_dotp, curwp->w_doto);
  306.                                 if (c>='A' && c<='Z') {
  307.                                         c += 'a'-'A';
  308.                                         lputc(curwp->w_dotp, curwp->w_doto, c);
  309.                                         lchange(WFHARD);
  310.                                 }
  311.                                 if (forwchar(FALSE, 1) == FALSE)
  312.                                         return (FALSE);
  313.                         }
  314.                 }
  315.         }
  316.         return (TRUE);
  317. }
  318.  
  319. /*
  320.  * Kill forward by "n" words. Remember the location of dot. Move forward by
  321.  * the right number of words. Put dot back where it was and issue the kill
  322.  * command for the right number of characters. Bound to "M-D".
  323.  */
  324. delfword(f, n)
  325. {
  326.         register int    size;
  327.         register LINE   *dotp;
  328.         register int    doto;
  329.  
  330.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  331.         return(rdonly());    /* we are in read only mode    */
  332.         if (n < 0)
  333.                 return (FALSE);
  334.         dotp = curwp->w_dotp;
  335.         doto = curwp->w_doto;
  336.         size = 0;
  337.         while (n--) {
  338. #if    NFWORD
  339.         while (inword() != FALSE) {
  340.             if (forwchar(FALSE,1) == FALSE)
  341.                 return(FALSE);
  342.             ++size;
  343.         }
  344. #endif
  345.                 while (inword() == FALSE) {
  346.                         if (forwchar(FALSE, 1) == FALSE)
  347.                                 return (FALSE);
  348.                         ++size;
  349.                 }
  350. #if    NFWORD == 0
  351.                 while (inword() != FALSE) {
  352.                         if (forwchar(FALSE, 1) == FALSE)
  353.                                 return (FALSE);
  354.                         ++size;
  355.                 }
  356. #endif
  357.         }
  358.         curwp->w_dotp = dotp;
  359.         curwp->w_doto = doto;
  360.         return (ldelete(size, TRUE));
  361. }
  362.  
  363. /*
  364.  * Kill backwards by "n" words. Move backwards by the desired number of words,
  365.  * counting the characters. When dot is finally moved to its resting place,
  366.  * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
  367.  */
  368. delbword(f, n)
  369. {
  370.         register int    size;
  371.  
  372.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  373.         return(rdonly());    /* we are in read only mode    */
  374.         if (n < 0)
  375.                 return (FALSE);
  376.         if (backchar(FALSE, 1) == FALSE)
  377.                 return (FALSE);
  378.         size = 0;
  379.         while (n--) {
  380.                 while (inword() == FALSE) {
  381.                         if (backchar(FALSE, 1) == FALSE)
  382.                                 return (FALSE);
  383.                         ++size;
  384.                 }
  385.                 while (inword() != FALSE) {
  386.                         if (backchar(FALSE, 1) == FALSE)
  387.                                 return (FALSE);
  388.                         ++size;
  389.                 }
  390.         }
  391.         if (forwchar(FALSE, 1) == FALSE)
  392.                 return (FALSE);
  393.         return (ldelete(size, TRUE));
  394. }
  395.  
  396. /*
  397.  * Return TRUE if the character at dot is a character that is considered to be
  398.  * part of a word. The word character list is hard coded. Should be setable.
  399.  */
  400. inword()
  401. {
  402.         register int    c;
  403.  
  404.         if (curwp->w_doto == llength(curwp->w_dotp))
  405.                 return (FALSE);
  406.         c = lgetc(curwp->w_dotp, curwp->w_doto);
  407.  
  408.         if (c>='a' && c<='z')
  409.                 return (TRUE);
  410.         if (c>='A' && c<='Z')
  411.                 return (TRUE);
  412.         if (c>='0' && c<='9')
  413.                 return (TRUE);
  414.         return (FALSE);
  415. }
  416.  
  417. fillpara(f, n)    /* Fill the current paragraph according to the current
  418.            fill column                        */
  419.  
  420. int f, n;    /* deFault flag and Numeric argument */
  421.  
  422. {
  423.     register int c;            /* current char durring scan    */
  424.     register int wordlen;        /* length of current word    */
  425.     register int clength;        /* position on line during fill    */
  426.     register int i;            /* index during word copy    */
  427.     register int newlength;        /* tentative new line length    */
  428.     register int eopflag;        /* Are we at the End-Of-Paragraph? */
  429.     register int firstflag;        /* first word? (needs no space)    */
  430.     register LINE *eopline;        /* pointer to line just past EOP */
  431.     register int dotflag;        /* was the last char a period?    */
  432.     char wbuf[NSTRING];        /* buffer for current word    */
  433.  
  434.  
  435.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  436.         return(rdonly());    /* we are in read only mode    */
  437.     if (fillcol == 0) {    /* no fill column set */
  438.         mlwrite("No fill column set");
  439.         return(FALSE);
  440.     }
  441.  
  442.     /* record the pointer to the line just past the EOP */
  443.     gotoeop(FALSE, 1);
  444.     eopline = lforw(curwp->w_dotp);
  445.  
  446.     /* and back to the beginning of the paragraph */
  447.     gotobop(FALSE, 1);
  448.  
  449.     /* let yank() know that it may be restoring a paragraph */
  450.     thisflag |= CFFILL;
  451.  
  452.     if(Pmaster == NULL)
  453.       sgarbk = TRUE;
  454.  
  455.         curwp->w_flag |= WFMODE;
  456.     kdelete();
  457.  
  458.     /* initialize various info */
  459.     clength = curwp->w_doto;
  460.     if (clength && curwp->w_dotp->l_text[0] == TAB)
  461.         clength = 8;
  462.     wordlen = 0;
  463.     dotflag = FALSE;
  464.  
  465.     /* scan through lines, filling words */
  466.     firstflag = TRUE;
  467.     eopflag = FALSE;
  468.  
  469.     while (!eopflag) {
  470.         /* get the next character in the paragraph */
  471.         if (curwp->w_doto == llength(curwp->w_dotp)) {
  472.  
  473.             c = ' ';
  474.             if (lforw(curwp->w_dotp) == eopline)
  475.                 eopflag = TRUE;
  476.             kinsert('\n');
  477.         } else {
  478.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  479.             kinsert(c);
  480.         }
  481.  
  482.         /* and then delete it */
  483.         ldelete(1, FALSE);
  484.  
  485.         /* if not a separator, just add it in */
  486.         if (c != ' ' && c != '    ') {
  487.             /* 
  488.              * don't want to limit ourselves to only '.'
  489.              */
  490.             dotflag = (int)strchr(".?!:;", c);    /* dot ? */
  491.             if (wordlen < NSTRING - 1)
  492.                 wbuf[wordlen++] = c;
  493.         } else if (wordlen) {
  494.             /* at a word break with a word waiting */
  495.             /* calculate tantitive new length with word added */
  496.             newlength = clength + 1 + wordlen;
  497.             if (newlength <= fillcol) {
  498.                 /* add word to current line */
  499.                 if (!firstflag) {
  500.                     linsert(1, ' '); /* the space */
  501.                     ++clength;
  502.                 }
  503.                 firstflag = FALSE;
  504.             } else {
  505.                 /* start a new line */
  506.                 lnewline();
  507.                 clength = 0;
  508.             }
  509.  
  510.             /* and add the word in in either case */
  511.             for (i=0; i<wordlen; i++) {
  512.                 linsert(1, wbuf[i]);
  513.                 ++clength;
  514.             }
  515.  
  516.             /*  Strategy:  Handle 3 cases:
  517.              *     1. if . at end of line put extra space after it
  518.              *     2. if . and only 1 space, leave only one space 
  519.              *     3. if . and more than 1 space, leave 2 spaces
  520.              *
  521.              *  So, we know the current c is a space. if then 
  522.              *  is no next c or the next c is a ' ' then we 
  523.              *  need to insert a space else don't do it.
  524.              */
  525.             if (dotflag &&
  526.                    ((curwp->w_doto == llength(curwp->w_dotp)) || 
  527.                (' ' == lgetc(curwp->w_dotp, curwp->w_doto)))){
  528.                 linsert(1, ' ');
  529.                 ++clength;
  530.             }
  531.             wordlen = 0;
  532.         }
  533.     }
  534.  
  535.     /* and add a last newline for the end of our new paragraph */
  536.     lnewline();
  537. }
  538.